In [1]:
import numpy as np

Conversion of Python list to numPy array


In [2]:
arr = np.array([2,5,6,8],
              dtype = int)
print(arr)
print(type(arr))
print(np.result_type(arr))
arr = arr.astype(complex)
print(np.result_type(arr))


[2 5 6 8]
<class 'numpy.ndarray'>
int32
complex128

Intrinsic numPy array Creation


In [3]:
print( np.zeros( (4,3) ) )
#float64 is a by default dtype
print(np.ones( (3,3), dtype = np.float64 ))
# arange() is a function similar to range()
# that returns arrays instead of lists
# It can accept float arguments too 
print(np.arange(0, 10, 1.33, dtype = np.float64))
# arange gives uncertain number of values based on steps
# Hence, linspace, which asks for number of values
print(np.linspace(0, 160, 5, dtype = np.float64))
# rand -> random values in a given shape
print(np.random.rand(1,3))


[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
[0.   1.33 2.66 3.99 5.32 6.65 7.98 9.31]
[  0.  40.  80. 120. 160.]
[[0.38581097 0.24211063 0.30579432]]

Matrix Creation


In [4]:
# Using reshape to convert array into matrix
print(np.array([5,6,8,45,12,52]).reshape(2,3))

# Using matrix function
print(np.matrix([[1,2],
                [3,4]]))
print(np.eye(3)) # Identity matrix


[[ 5  6  8]
 [45 12 52]]
[[1 2]
 [3 4]]
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

Vectorized Operations


In [5]:
arr1 = np.array([150, 200, 30])
arr2 = np.arange( 3 )
print(arr1,arr2)
print(arr1 - arr2)

print(arr2**3)

print(arr2 < 1)
# Gives the index where new value can be placed to
# preserve order
print(np.searchsorted(arr1, 100))
print(np.searchsorted(arr2, 100))


[150 200  30] [0 1 2]
[150 199  28]
[0 1 8]
[ True False False]
0
3

Matrix multiplication


In [6]:
mat1 = np.array([[1, 2],
                [3, 4]])
mat2 = np.array([[2, 3],
                [5, 6]])
print(mat1 * mat2)  # Elementwise product
print(mat1.dot(mat2))   # Dot product
print(np.dot(mat1,mat2)) # Dot product


[[ 2  6]
 [15 24]]
[[12 15]
 [26 33]]
[[12 15]
 [26 33]]

Shorthand operations


In [7]:
arr1 = np.ones((2,3), dtype = float)
arr1 *= 5
print(arr1)
arr1 += 5
print(arr1)


[[5. 5. 5.]
 [5. 5. 5.]]
[[10. 10. 10.]
 [10. 10. 10.]]

Comparison operations


In [8]:
mat1 = np.matrix([[0, 20],
                 [3, -6]])
mat2 = np.matrix([[1, 12],
                 [0.30, 4]])
print(np.greater_equal(mat1, mat2))
print(np.less(mat1, mat2))
print(np.equal(mat1, mat2))
print(np.not_equal(mat1, mat2))


[[False  True]
 [ True False]]
[[ True False]
 [False  True]]
[[False False]
 [False False]]
[[ True  True]
 [ True  True]]

Logical Operations


In [9]:
print(np.logical_and(1, False))
print(np.logical_or(1, 0))
print(np.logical_not(1))
print(np.logical_xor(1, 0))


False
True
False
True

Universal functions


In [10]:
mat1 = np.matrix([[1, 2],
                 [3, 4]])

print(mat1.sum())
print(mat1.min())
print(mat1.max())

print(mat1.shape)


10
1
4
(2, 2)

In [11]:
# Using AXIS to specify the direction
# 0 -> Vertical
# 1 -> Horizontal 

print(mat1.sum(axis = 0))
print(mat1.sum(axis = 0).shape)


[[4 6]]
(1, 2)

In [12]:
print(mat1.sum(axis = 1))
print(mat1.sum(axis = 1).shape)


[[3]
 [7]]
(2, 1)

In [13]:
print(mat1.cumsum(axis = 0))
print(mat1.cumsum(axis = 1))


[[1 2]
 [4 6]]
[[1 3]
 [3 7]]

In [14]:
print(np.sqrt(mat1))
print(np.sin(mat1))
print(np.sin(np.pi/2))


[[1.         1.41421356]
 [1.73205081 2.        ]]
[[ 0.84147098  0.90929743]
 [ 0.14112001 -0.7568025 ]]
1.0

Matrix attributes


In [15]:
mat1 = np.matrix([[1.2, 2+6j],
                 [3+5j, 4]], dtype = complex)
mat2 = np.matrix([[1, 2],
                 [3, 4]], dtype = int)

In [16]:
print(mat1.ndim)    # Number of dimensions
print(mat1.size)    # Number of elements
print(mat1.T)   # Transpose
print(mat1.A1)  # 1D array
print(mat1.H)   # Complex conjugate transpose

print(mat1.imag)    # imag part
print(mat1.real)    # real part
print(abs(mat1))    # Absolute value

print(mat1.itemsize) # total bytes occupied by 1 ele
print(mat1.nbytes)  # total bytes consumed by matrix
print(mat2.nbytes)


2
4
[[1.2+0.j 3. +5.j]
 [2. +6.j 4. +0.j]]
[1.2+0.j 2. +6.j 3. +5.j 4. +0.j]
[[1.2-0.j 3. -5.j]
 [2. -6.j 4. -0.j]]
[[0. 6.]
 [5. 0.]]
[[1.2 2. ]
 [3.  4. ]]
[[1.2        6.32455532]
 [5.83095189 4.        ]]
16
64
16

Matrix methods


In [17]:
mat1 = np.arange(9, dtype = np.float64).reshape(3,3)
mat2 = np.array([[1, 2+3j],
                [3-9j,2]], dtype = complex)
mat3 = np.array([[1, 4],
                [3, 2]])
mat4 = np.array([[10, 40],
                [30, 20]])

In [18]:
print(mat1)
print(mat1.diagonal()) # Parameters -> 1, -1, 2, -2
print(np.trace(mat1))   # Sum of diag. ele.

print(mat1.compress([True,False,True],axis = 0)) #row
print(mat1.compress([True,False,True],axis = 1)) #col

print(mat2.conjugate())


[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]
[0. 4. 8.]
12.0
[[0. 1. 2.]
 [6. 7. 8.]]
[[0. 2.]
 [3. 5.]
 [6. 8.]]
[[1.-0.j 2.-3.j]
 [3.+9.j 2.-0.j]]

Indexing is alternate to itemset


In [19]:
mat1.itemset(5,98)  # counts in row axis @ pos 5th
mat1.itemset( (2,1), 45) # @ pos (2,1)
print(mat1)

mat3.sort(axis = 0) # Col wise
print(mat3)
mat4.sort(axis = 1) # Row wise
print(mat4)


[[ 0.  1.  2.]
 [ 3.  4. 98.]
 [ 6. 45.  8.]]
[[1 2]
 [3 4]]
[[10 40]
 [20 30]]

Indexing & Slicing

1-D array


In [20]:
arr1 = np.array([2, 5, 6, 4, 3])
print(arr1[2])
print(arr1[1:3])
print(arr1[1:4:2])  # Every 2nd ele
print(arr1[::2])    
print(arr1[::-1])   # Reversed array
print(arr1[::-2])   # Reversed array (every 2nd ele)


6
[5 6]
[5 4]
[2 6 3]
[3 4 6 5 2]
[3 6 2]

Multidimensional array


In [21]:
mat1 = np.arange( 9 ).reshape(3,3)
print(mat1)
print(mat1[2,2])
print(mat1[:,2])
print(mat1[1,:])
print(mat1[0:2,2])  # doesn't consider last row
print(type(mat1[1,:].shape))


[[0 1 2]
 [3 4 5]
 [6 7 8]]
8
[2 5 8]
[3 4 5]
[2 5]
<class 'tuple'>

Advanced indexing


In [22]:
arr1 = np.array([52, 65, 89, 78, 45, 11, 23, 96])
arr1_ind = [1, 3, 5]
# Passing array as index
print(arr1[arr1_ind])


[65 78 11]

In [23]:
arr1_ind = [1, 3, 5]
# assigning values to index of array
arr1[arr1_ind] = [-50, -60, -70]
print(arr1)


[ 52 -50  89 -60  45 -70  23  96]

Condition based indexing


In [24]:
arr1_ind = arr1 > 50
print(arr1)
print(arr1[arr1_ind])


[ 52 -50  89 -60  45 -70  23  96]
[52 89 96]

Repetitive index


In [25]:
arr1_ind = [0,0,2,3]
arr1[arr1_ind] = [100, 200, 300, 400] 
print(arr1)


[200 -50 300 400  45 -70  23  96]

Indexing on matrix


In [26]:
mat1 = np.array([[ 0,  1,  2,  3],
                [ 4,  5,  6,  7],
                [ 8,  9, 10, 11]])
# size of indA and indB must be equal

indA = np.array([[2,2],[1,1]])
indB = np.array([[2,1],[1,0]])

print(mat1[indA, indB])
print(mat1[indA, 1])
print(mat1[:, indB])
mat1[indA, indB] = np.array([[100, 90],[50, 40]])
print(mat1)


[[10  9]
 [ 5  4]]
[[9 9]
 [5 5]]
[[[ 2  1]
  [ 1  0]]

 [[ 6  5]
  [ 5  4]]

 [[10  9]
  [ 9  8]]]
[[  0   1   2   3]
 [ 40  50   6   7]
 [  8  90 100  11]]

Manipulations

Shape conversion


In [27]:
mat1 = np.arange( 4 ).reshape(2,2)
print(np.array(mat1.flat)) # Gives 1D array
print(np.array(mat1.ravel()))  # Gives 1D array
# With -1 other dim are  calc. automatically
print(mat1.reshape(4,-1).shape)
print(mat1.reshape(-1,4).shape) 
print(mat1)     # No perm. change to mat1 yet
mat1.resize( (1,4) )    # Perm. change
print(mat1)


[0 1 2 3]
[0 1 2 3]
(4, 1)
(1, 4)
[[0 1]
 [2 3]]
[[0 1 2 3]]

Stacking arrays to form matrix


In [28]:
arr1 = np.array([[1, 2],
                [3, 4]])
arr2 = np.array([[10, 20],
                [30, 40]])

VSTACK -> adds row(s)


In [29]:
# even matrix and 1D arrays can be stacked
matR = np.vstack( (arr1, arr2) ) 
print(matR)
print(matR.shape)


[[ 1  2]
 [ 3  4]
 [10 20]
 [30 40]]
(4, 2)

HSTACK -> adds col(s)


In [30]:
matC = np.hstack( (arr1, arr2) ) 
print(matC)
print(matC.shape)


[[ 1  2 10 20]
 [ 3  4 30 40]]
(2, 4)

Splitting of arrays


In [31]:
arr1 = np.arange(16).reshape(4,4)

VSPLIT -> Split row wise


In [32]:
matR = np.vsplit(arr1,4)
print(np.array(matR))
print(np.array(matR).shape)
print(matR[0][0][2]) # Currently, a normal list


[[[ 0  1  2  3]]

 [[ 4  5  6  7]]

 [[ 8  9 10 11]]

 [[12 13 14 15]]]
(4, 1, 4)
2

HSPLIT -> Split col wise


In [33]:
matR = np.hsplit(arr1,4)
print(np.array(matR))
print(np.array(matR).shape)
print(matR[0][1][0]) # Currently, a normal list


[[[ 0]
  [ 4]
  [ 8]
  [12]]

 [[ 1]
  [ 5]
  [ 9]
  [13]]

 [[ 2]
  [ 6]
  [10]
  [14]]

 [[ 3]
  [ 7]
  [11]
  [15]]]
(4, 4, 1)
4

Copying the value


In [34]:
arr1 = np.arange(12).reshape(4,3)
arr2 = arr1
print(arr2 is arr1)
arr2[2,2] = 50 
# mutability plays its role
print(arr1)


True
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7 50]
 [ 9 10 11]]

Deep copy


In [35]:
arr1 = np.arange(12).reshape(4,3)
arr2 = arr1.copy()
print(arr2 is arr1)
arr2[2,2] = 50 
print(arr1)
print(arr2)


False
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7 50]
 [ 9 10 11]]

Linear Algebra


In [36]:
mat1 = np.arange(4).reshape(2,2)
mat2 = (np.arange(4)*2).reshape(2,2)
mat3 = (np.arange(4)*3).reshape(2,2)

Performing multiple dot product in one go


In [37]:
print(np.linalg.multi_dot( [mat1, mat2, mat3] ))


[[ 36  66]
 [132 234]]

Finding Inverse of matrix


In [38]:
print(np.linalg.inv(mat2))


[[-0.75  0.25]
 [ 0.5   0.  ]]

Computing real eigenvalues and eigenvectors


In [39]:
e1, e2 = np.linalg.eig(np.diag( (1, 2, 3) ))
print(e2)
print(e1)


[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
[1. 2. 3.]

Alternate method to get evalues


In [40]:
print(np.linalg.eigvals(np.diag( (1, 2, 3) )))


[1. 2. 3.]

Computing determinant of matrix


In [41]:
print(np.linalg.det(mat1))


-2.0

Computing matrix rank


In [42]:
print(np.linalg.matrix_rank(mat1))


2

Solving system of linear equations


In [43]:
# 3x + y = 9
# x + 2y = 8

a = np.array([[3, 1],[1, 2]])
b = np.array([9, 8])
print(np.linalg.solve(a, b))


[2. 3.]